package org.example.project.common.error.enums;

import lombok.ToString;
import org.example.project.common.error.MessageEnum;

/**
 * 参考Java开发手册，错误码：
 * <p>
 * 1. 【强制】错误码为字符串类型,共 5 位,分成两个部分:错误产生来源+四位数字编号
 * 说明:错误产生来源分为 A/B/C,
 * A 表示错误来源于用户,比如参数错误,用户安装版本过低等问题;
 * B 表示错误来源于当前系统,往往是业务逻辑出错,或程序健壮性差等问题;
 * C 表示错误来源于第三方服务,比如 CDN 服务出错,消息投递超时等问题;
 * 四位数字编号从 0001 到 9999,大类之间的步长间距预留 100
 * <p>
 * 2. 【强制】全部正常,但不得不填充错误码时返回五个零:00000
 * <p>
 * 3. 【参考】错误码分为一级宏观错误码、二级宏观错误码、三级宏观错误码。
 * 说明:在无法更加具体确定的错误场景中,可以直接使用一级宏观错误码,
 * 分别是:A0001(用户端错误)、B0001(系统执行出错)、C0001(调用第三方服务出错)。
 *
 * @author wenxy
 * @date 2020/9/28
 */
@ToString
public enum ErrorCode implements MessageEnum {

    /**
     * 一级宏观码
     */
    SUCCESS("00000", "操作成功"),
    A0001("A0001", "用户端错误"),
    B0001("B0001", "系统执行出错"),
    C0001("C0001", "调用第三方服务出错"),

    /**
     * 二级、三级宏观码
     */
    /****************************************************************/
    // 用户
    A0100("A0100", "用户注册失败"),
    A0200("A0200", "用户登录异常"),

    A0300("A0300", "访问权限异常"),
    A0301("A0301", "访问未授权"),
    A0303("A0303", "用户授权申请被拒绝"),

    A0310("A0310", "因访问对象隐私设置被拦截"),
    A0311("A0311", "授权已过期"),
    A0312("A0312", "无权限使用API"),

    A0320("A0320", "用户访问被拦截"),
    A0321("A0321", "黑名单用户"),
    A0322("A0322", "账号被冻结"),
    A0323("A0323", "非法IP地址"),
    A0324("A0324", "网关访问受限"),

    A0330("A0330", "服务已欠费"),
    A0340("A0340", "用户签名异常"),
    A0341("A0341", "RSA签名错误"),

    A0400("A0400", "用户请求参数错误"),
    A0402("A0402", "无效的用户输入"),

    A0410("A0410", "请求必填参数为空"),
    A0411("A0411", "用户订单号为空"),
    A0413("A0413", "缺少时间戳参数"),
    A0414("A0414", "非法的时间戳参数"),

    A0420("A0420", "请求参数值超出允许的范围"),
    A0421("A0421", "参数格式不匹配"),
    A0422("A0422", "地址不在服务范围"),
    A0423("A0423", "时间不在服务范围"),
    A0424("A0424", "金额超出限制"),
    A0425("A0425", "数量超出限制"),
    A0426("A0426", "请求批量处理总个数超出限制"),
    A0427("A0427", "请求JSON解析失败"),

    A0430("A0430", "用户输入内容非法"),
    A0440("A0440", "用户操作异常"),

    A0500("A0500", "用户请求服务异常"),
    A0501("A0501", "请求次数超出限制"),
    A0502("A0502", "请求并发数超出限制"),
    A0506("A0506", "用户重复请求"),

    A0600("A0600", "用户资源异常"),
    A0605("A0605", "用户配额已用光"),

    A0700("A0700", "用户上传文件异常"),
    A0800("A0800", "用户当前版本异常"),
    // 用户端未授予权限服务端无法正常交互
    A0900("A0900", "用户隐私未授权"),
    A1000("A1000", "用户设备异常"),

    /*****************************************************************/
    // 系统
    B0100("B0100", "系统执行超时"),
    B0101("B0101", "系统订单处理超时"),

    B0200("B0200", "系统容灾功能被触发"),
    B0210("B0210", "系统限流"),
    B0220("B0220", "系统功能降级"),

    B0300("B0300", "系统资源异常"),
    B0310("B0310", "系统资源耗尽"),

    B0320("B0320", "系统资源访问异常"),
    B0321("B0321", "系统读取磁盘文件失败"),

    /****************************************************************/
    // 第三方
    C0100("C0100", "中间件服务出错"),

    C0110("C0110", "RPC服务出错"),
    C0111("C0111", "RPC服务未找到"),
    C0112("C0112", "RPC服务未注册"),
    C0113("C0113", "接口不存在"),

    C0120("C0120", "消息服务出错"),
    C0121("C0121", "消息投递出错"),
    C0122("C0122", "消息消费出错"),
    C0123("C0123", "消息订阅出错"),
    C0124("C0124", "消息分组未查到"),

    C0130("C0130", "缓存服务出错"),
    C0131("C0131", "key长度超过限制"),
    C0132("C0132", "value长度超过限制"),
    C0133("C0133", "存储容量已满"),
    C0134("C0134", "不支持的数据格式"),

    C0140("C0140", "配置服务出错"),

    C0150("C0150", "网络资源服务出错"),
    C0151("C0151", "VPN服务出错"),
    C0152("C0152", "CDN服务出错"),
    C0153("C0153", "域名解析服务出错"),
    C0154("C0154", "网关服务出错"),

    C0200("C0200", "第三方系统执行超时"),
    C0210("C0210", "RPC执行超时"),
    C0220("C0220", "消息投递超时"),
    C0230("C0230", "缓存服务超时"),
    C0240("C0240", "配置服务超时"),
    C0250("C0250", "数据库服务超时"),

    C0300("C0300", "数据库服务出错"),
    C0311("C0311", "表不存在"),
    C0321("C0321", "多表关联中存在多个相同名称的列"),
    C0331("C0331", "数据库死锁"),
    C0341("C0341", "主键冲突"),

    C0400("C0400", "第三方容灾系统被触发"),
    C0401("C0401", "第三方系统限流"),
    C0402("C0402", "第三方功能降级"),

    C0500("C0500", "通知服务出错"),
    C0501("C0501", "短信提醒服务失败"),
    C0502("C0502", "语音提醒服务失败"),
    C0503("C0503", "邮件提醒服务失败"),

    ;

    final String code;
    final String msg;

    ErrorCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }


    @Override
    public String code() {
        return code;
    }

    @Override
    public String msg() {
        return msg;
    }

    public static boolean isSuccess(String code) {
        return SUCCESS.code.equals(code);
    }

    @Override
    public Boolean isClientError() {
        return code.startsWith("A");
    }
}
